package org.jsola.hr.service.impl;

import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IUserReadCompanySysNoticeDAO;
import org.jsola.hr.dto.UserReadCompanySysNoticeAddDTO;
import org.jsola.hr.dto.UserReadCompanySysNoticeUpdateDTO;
import org.jsola.hr.entity.CompanySysNoticeDO;
import org.jsola.hr.entity.UserReadCompanySysNoticeDO;
import org.jsola.hr.query.UserReadCompanySysNoticeQuery;
import org.jsola.hr.service.ICompanySysNoticeService;
import org.jsola.hr.service.IUserReadCompanySysNoticeService;
import org.jsola.hr.vo.UserReadCompanySysNoticeListVO;
import org.jsola.hr.vo.UserReadCompanySysNoticeVO;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户已阅公司系统公告(用户阅读公司系统公告后添加)
 *
 * @author zhr
 */
@Service("hrUserReadCompanySysNoticeServiceImpl")
public class UserReadCompanySysNoticeServiceImpl implements IUserReadCompanySysNoticeService {

    @Autowired
    private IUserReadCompanySysNoticeDAO userReadCompanySysNoticeDAO;

    @Autowired
    private ICompanySysNoticeService companySysNoticeService;

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public UserReadCompanySysNoticeVO save(UserReadCompanySysNoticeAddDTO userReadCompanySysNoticeAddDTO, TokenUser tokenUser) {
        // 转DO
        UserReadCompanySysNoticeDO userReadCompanySysNoticeDO = userReadCompanySysNoticeAddDTO.to(UserReadCompanySysNoticeDO.class);
        // 保存
        userReadCompanySysNoticeDO = save(userReadCompanySysNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());
        return userReadCompanySysNoticeDO.to(UserReadCompanySysNoticeVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(UserReadCompanySysNoticeUpdateDTO userReadCompanySysNoticeUpdateDTO, TokenUser tokenUser) {
        //转DO
        UserReadCompanySysNoticeDO userReadCompanySysNoticeDO = userReadCompanySysNoticeUpdateDTO.to(UserReadCompanySysNoticeDO.class);
        //根据主键更新，只更新非null值
        return updateByIdSelective(userReadCompanySysNoticeDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... userReadCompanySysNoticeIds) {
        return deleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) userReadCompanySysNoticeIds);
    }


    @Override
    public UserReadCompanySysNoticeVO selectById(String userReadCompanySysNoticeId, String siteId) {
        UserReadCompanySysNoticeDO userReadCompanySysNoticeDO = selectDOById(userReadCompanySysNoticeId, siteId);
        if (userReadCompanySysNoticeDO == null) {
            return null;
        }
        return userReadCompanySysNoticeDO.to(UserReadCompanySysNoticeVO.class);
    }

    @Override
    public List<UserReadCompanySysNoticeListVO> select(UserReadCompanySysNoticeQuery userReadCompanySysNoticeQuery, String siteId) {
        List<UserReadCompanySysNoticeDO> userReadCompanySysNoticeDOList = selectDO(userReadCompanySysNoticeQuery, siteId);
        if(CollectionUtils.isEmpty(userReadCompanySysNoticeDOList)) {
            return userReadCompanySysNoticeDOList == null ? null : new ArrayList<>();
        }
        return userReadCompanySysNoticeDOList.stream()
                .map(userReadCompanySysNoticeDO -> userReadCompanySysNoticeDO.to(UserReadCompanySysNoticeListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(UserReadCompanySysNoticeQuery userReadCompanySysNoticeQuery, String siteId) {
        Example example = buildExample(userReadCompanySysNoticeQuery,siteId);
        return userReadCompanySysNoticeDAO.selectCountByExample(example);
    }

    @Override
    public Page<UserReadCompanySysNoticeListVO> selectPage(UserReadCompanySysNoticeQuery userReadCompanySysNoticeQuery, String siteId) {
        Example example = buildExample(userReadCompanySysNoticeQuery,siteId);
        Page<UserReadCompanySysNoticeDO> page = userReadCompanySysNoticeDAO.selectPageByExample(example,
                userReadCompanySysNoticeQuery.getPageNo(),
                userReadCompanySysNoticeQuery.getPageSize());

        return page.to(UserReadCompanySysNoticeListVO.class);
    }

    @Override
    public UserReadCompanySysNoticeDO selectDOById(String userReadCompanySysNoticeId, String siteId) {
        return listById(userReadCompanySysNoticeId, siteId);
    }

    @Override
    public List<UserReadCompanySysNoticeDO> selectDO(UserReadCompanySysNoticeQuery userReadCompanySysNoticeQuery, String siteId) {
        Example example = buildExample(userReadCompanySysNoticeQuery,siteId);
        return userReadCompanySysNoticeDAO.selectByExample(example);
    }

    @Override
    public List<UserReadCompanySysNoticeDO> listBySysNoticeIds(TokenUser tokenUser, String... sysNoticeIds) {
        if (sysNoticeIds == null || sysNoticeIds.length == 0) {
            return new ArrayList<>();
        }
        Example example = new Example(UserReadCompanySysNoticeDO.class);
        example.and()
                .andIn("sysNoticeId", Arrays.asList(sysNoticeIds))
                .andEqualTo("userId", tokenUser.getUserId())
                .andEqualTo("hasDel", false)
                .andEqualTo("siteId", tokenUser.getSiteId());
        return userReadCompanySysNoticeDAO.selectByExample(example);
    }

    @Override
    public UserReadCompanySysNoticeDO findBySysNoticeId(String sysNoticeId, TokenUser tokenUser) {
        Example example = new Example(UserReadCompanySysNoticeDO.class);
        example.and()
                .andEqualTo("sysNoticeId", sysNoticeId)
                .andEqualTo("userId", tokenUser.getUserId())
                .andEqualTo("siteId", tokenUser.getSiteId());
        return userReadCompanySysNoticeDAO.selectOneByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void readSysNotice(String sysNoticeId, TokenUser tokenUser) {
        CompanySysNoticeDO sysNotice = companySysNoticeService.selectDOById(sysNoticeId, tokenUser.getSiteId());
        ParamException.notNull(sysNotice, "公司公告不存在或已删除");

        if (!sysNotice.getIsOnline() || sysNotice.getStatus() != 1) {
            throw new ParamException("公司公告状态不正确,未上线或未发布");
        }
        UserReadCompanySysNoticeDO readSysNotice = findBySysNoticeId(sysNoticeId, tokenUser);
        if (Objects.nonNull(readSysNotice)) {
            return;
        }
        // 添加已读记录
        UserReadCompanySysNoticeAddDTO addDTO = new UserReadCompanySysNoticeAddDTO();
        addDTO.setSysNoticeId(sysNoticeId);
        addDTO.setUserId(tokenUser.getUserId());
        addDTO.setHasDel(false);
        save(addDTO, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteUserSysNotice(TokenUser tokenUser, String... sysNoticeIds) {
        // 先筛选存在的公告
        List<CompanySysNoticeDO> sysNoticeList = companySysNoticeService.listBySysNoticeIds(tokenUser.getSiteId(), sysNoticeIds);
        ParamException.notEmpty(sysNoticeList, "没有需要删除的公告");
        // 已发布已上线的公告id
        List<String> sysNoticeIdList = sysNoticeList.parallelStream()
                .filter(companySysNotice -> companySysNotice.getIsOnline() && companySysNotice.getStatus() == 1)
                .map(CompanySysNoticeDO::getId)
                .collect(Collectors.toList());
        ParamException.notEmpty(sysNoticeIdList, "没有需要删除的已发布的公告");

        Example example = new Example(UserReadCompanySysNoticeDO.class);
        example.and()
                .andIn("sysNoticeId", sysNoticeIdList)
                .andEqualTo("userId", tokenUser.getUserId())
                .andEqualTo("siteId", tokenUser.getSiteId());
        // 已读的公告
        List<UserReadCompanySysNoticeDO> readCompanySysNoticeList = userReadCompanySysNoticeDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(readCompanySysNoticeList)) {
            // 状态置为删除
            UserReadCompanySysNoticeDO updateDO = new UserReadCompanySysNoticeDO();
            updateDO.setHasDel(true);
            userReadCompanySysNoticeDAO.updateByExampleSelective(updateDO, example);
            // 已读的系统公告id
            List<String> readSysNoticeIdList = readCompanySysNoticeList.parallelStream()
                    .map(UserReadCompanySysNoticeDO::getSysNoticeId)
                    .collect(Collectors.toList());
            // 移除已读的,剩下未读的
            sysNoticeIdList.removeAll(readSysNoticeIdList);
        }
        if (!CollectionUtils.isEmpty(sysNoticeIdList)) {
            // 剩下未读的,添加已读并且删除记录
            List<UserReadCompanySysNoticeDO> noReadSysNoticeList = sysNoticeIdList.parallelStream()
                    .map(sysNoticeId -> {
                        UserReadCompanySysNoticeDO userCompanySysNoticeDO = new UserReadCompanySysNoticeDO();
                        userCompanySysNoticeDO.setSysNoticeId(sysNoticeId);
                        userCompanySysNoticeDO.setUserId(tokenUser.getUserId());
                        userCompanySysNoticeDO.setHasDel(true);

                        userCompanySysNoticeDO.preInsert(tokenUser.getUserId());
                        userCompanySysNoticeDO.setSiteId(tokenUser.getSiteId());

                        return userCompanySysNoticeDO;
                    }).collect(Collectors.toList());
            userReadCompanySysNoticeDAO.insertListAndSetId(noReadSysNoticeList);
        }
    }


    /**
     * 根据查询参数，构建example

     * @param userReadCompanySysNoticeQuery 查询参数
     * @param siteId 所属站点id
     * @return example
     */
    private Example buildExample(UserReadCompanySysNoticeQuery userReadCompanySysNoticeQuery, String siteId) {
        Example example = new Example(UserReadCompanySysNoticeDO.class);
        example.and()
                .andEqualTo("siteId", siteId);
        if (userReadCompanySysNoticeQuery.getUserId() != null) {
            example.and().andEqualTo("userId", userReadCompanySysNoticeQuery.getUserId());
        }
        if (userReadCompanySysNoticeQuery.getSysNoticeId() != null) {
            example.and().andEqualTo("sysNoticeId", userReadCompanySysNoticeQuery.getSysNoticeId());
        }
        if (userReadCompanySysNoticeQuery.getHasDel() != null) {
            example.and().andEqualTo("hasDel", userReadCompanySysNoticeQuery.getHasDel());
        }
        // 排序
        ExampleKit.setExampleOrder(example,userReadCompanySysNoticeQuery.getOrders());
        return example;
    }
}




